package l2ft.gameserver.database;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class MySql
{
	private static final Logger _log = LoggerFactory.getLogger(MySql.class);

	public static boolean setEx(String query, Object... vars)
	{
		try(Connection con = DatabaseFactory.getConnection())
		{
			if(vars.length == 0)
			{
				try(Statement statement = con.createStatement())
				{
					statement.executeUpdate(query);
				}
			}
			else
			{

				try(PreparedStatement statement = con.prepareStatement(query))
				{
					setVars(statement, vars);
					statement.executeUpdate();
				}
			}
		}
		catch(Exception e)
		{
			_log.warn("Could not execute update '" + query + "': " + e);
			e.printStackTrace();
			return false;
		}
		return true;
	}

	public static void setVars(PreparedStatement statement, Object... vars) throws SQLException
	{
		Number n;
		long long_val;
		double double_val;
		for(int i = 0; i < vars.length; i++)
			if(vars[i] instanceof Number)
			{
				n = (Number) vars[i];
				long_val = n.longValue();
				double_val = n.doubleValue();
				if(long_val == double_val)
					statement.setLong(i + 1, long_val);
				else
					statement.setDouble(i + 1, double_val);
			}
			else if(vars[i] instanceof String)
				statement.setString(i + 1, (String) vars[i]);
	}

	public static boolean set(String query, Object... vars)
	{
		return setEx(query, vars);
	}

	public static boolean set(String query)
	{
		return setEx(query);
	}

	public static Object get(String query)
	{
		Object ret = null;
		
		try(Connection con = DatabaseFactory.getConnection();
				PreparedStatement statement = con.prepareStatement(query + " LIMIT 1"))
		{
			
			try(ResultSet rset = statement.executeQuery())
			{
				ResultSetMetaData md = rset.getMetaData();
	
				if(rset.next())
					if(md.getColumnCount() > 1)
					{
						Map<String, Object> tmp = new HashMap<String, Object>();
						for(int i = md.getColumnCount(); i > 0; i--)
							tmp.put(md.getColumnName(i), rset.getObject(i));
						ret = tmp;
					}
					else
						ret = rset.getObject(1);
			}
		}
		catch(Exception e)
		{
			_log.warn("Could not execute query '" + query + "': " + e);
			e.printStackTrace();
		}
		return ret;
	}

	public static List<Map<String, Object>> getAll(String query)
	{
		List<Map<String, Object>> ret = new ArrayList<Map<String, Object>>();
		
		try(Connection con = DatabaseFactory.getConnection();
				PreparedStatement statement = con.prepareStatement(query);
				ResultSet rset = statement.executeQuery())
		{
			
			ResultSetMetaData md = rset.getMetaData();
	
			while(rset.next())
			{
				Map<String, Object> tmp = new HashMap<String, Object>();
				for(int i = md.getColumnCount(); i > 0; i--)
					tmp.put(md.getColumnName(i), rset.getObject(i));
				ret.add(tmp);
			}
		}
		catch(Exception e)
		{
			_log.warn("Could not execute query '" + query + "': " + e);
			e.printStackTrace();
		}
		return ret;
	}

	public static List<Object> get_array(String query)
	{
		List<Object> ret = new ArrayList<Object>();

		try(Connection con = DatabaseFactory.getConnection();
				PreparedStatement statement = con.prepareStatement(query);
				ResultSet rset = statement.executeQuery())
		{

			ResultSetMetaData md = rset.getMetaData();

			while(rset.next())
			{
				if(md.getColumnCount() > 1)
				{
					Map<String, Object> tmp = new HashMap<String, Object>();
					for(int i = 0; i < md.getColumnCount(); i++)
						tmp.put(md.getColumnName(i + 1), rset.getObject(i + 1));
					ret.add(tmp);
				}
				else
					ret.add(rset.getObject(1));
			}
		}
		catch(Exception e)
		{
			_log.warn("Could not execute query '" + query + "': " + e);
			e.printStackTrace();
		}
		return ret;
	}

	public static int simple_get_int(String ret_field, String table, String where)
	{
		String query = "SELECT " + ret_field + " FROM `" + table + "` WHERE " + where + " LIMIT 1;";

		int res = 0;

		try(Connection con = DatabaseFactory.getConnection();
				PreparedStatement statement = con.prepareStatement(query);
				ResultSet rset = statement.executeQuery())
		{
			if(rset.next())
				res = rset.getInt(1);
		}
		catch(Exception e)
		{
			_log.warn("mSGI: Error in query '" + query + "':" + e);
			e.printStackTrace();
		}

		return res;
	}

	public static Integer[][] simple_get_int_array(String[] ret_fields, String table, String where)
	{
		String fields = null;
		for(String field : ret_fields)
			if(fields != null)
			{
				fields += ",";
				fields += "`" + field + "`";
			}
			else
				fields = "`" + field + "`";

		String query = "SELECT " + fields + " FROM `" + table + "` WHERE " + where;

		Integer res[][] = null;

		try(Connection con = DatabaseFactory.getConnection();
				PreparedStatement statement = con.prepareStatement(query);
				ResultSet rset = statement.executeQuery())
		{

			List<Integer[]> al = new ArrayList<Integer[]>();
			int row = 0;
			while(rset.next())
			{
				Integer[] tmp = new Integer[ret_fields.length];
				for(int i = 0; i < ret_fields.length; i++)
					tmp[i] = rset.getInt(i + 1);
				al.add(row, tmp);
				row++;
			}

			res = al.toArray(new Integer[row][ret_fields.length]);
		}
		catch(Exception e)
		{
			_log.warn("mSGIA: Error in query '" + query + "':" + e);
			e.printStackTrace();
		}

		return res;
	}
	
	public static void simple_update(String query)
	{
		try(Connection con = DatabaseFactory.getConnection();
				PreparedStatement statement = con.prepareStatement(query))
		{
			statement.execute();
		}
		catch(SQLException e)
		{
			_log.error("MySql: Error in query: "+query, e);
		}
	}
}